\subsection{Ejercicio 1}


Este filtro tiene como objetivo realizar un recorte de la imagen y voltearla (flip) verticalmente. El recorte est\'a definido por cuatro par\'ametros de entrada: el par \textit{offsetx} y \textit{offsety}, que indican respectivamente a partir de qu\'e columna y de qu\'e fila se recorta;  y el par \textit{tamx} y \textit{tamy}, que indican las dimensiones de la imagen recortada. 		


\subsubsection{Implementaci\'on en C}

La implementaci\'on en C es bastante directa. Se realiza un doble ciclo anidado a trav\'es de la parte de la imagen que se quiere recortar y se copian, componente a componente\footnote{es decir cada uno de los cuatro bytes que componen el p\'ixel, R, G, B y alpha}, los valores de la imagen origen en la imagen destino, realizando el flip vertical. El pseudoc\'odigo es el siguiente:

\begin{codesnippet}
\begin{verbatim}

    Para i = 0 hasta el Alto de la Imagen Destino (tamy); Paso: i++
        Para j = 0 hasta Ancho de la Imagen Destino * 4 (tamx); Paso: j ++

        Escribir en el byte (tamy - i - 1, j) de la matriz de la imagen destino 
        el componente (i + offsety, j + offsetx*4) de la matriz de la imagen fuente
		
        Fin Para
    Fin Para
\end{verbatim}
\end{codesnippet}

N\'otese que la cantidad de bytes que guardan componentes de la imagen destino resulta de multiplicar su cantidad de columnas por 4, ya que un p\'ixel consta de 3 componentes de color m\'as un byte de transparencia.

\subsubsection{Implementaci\'on en ASM}

La implementaci\'on en asm tiene una diferencia importante con respecto a la recientemente vista: realiza el pasaje de componentes de a 16 bytes. Para ello, como la versi\'on en C, tambi\'en implementa dos ciclos anidados: por las filas y por las columnas a recortar. Cada uno de estos ciclos se vale de un registro como contador, que se inicializa con la cantidad de filas y de componentes en una fila\footnote{cantidad de columnas multiplicado por 4}. Al final de cada iteraci\'on se reducen estos contadores hasta llegar a 0, momento que indica que se han procesado todas las filas o todas las columnas de una fila, seg\'un se trate del ciclo exterior o del interior.

Para el caso del ciclo exterior (filas), se tiene en R12d el \textit{tamy}, es decir, la cantidad de filas a recortar. \'Este se obtiene directamente del par\'ametro de la funci\'on. Como se trata del octavo par\'ametro entero se encuentra en la pila en la posici\'on [RBP + 24].

Para el caso del ciclo interior (columnas o componentes de las filas) se usa el registro RAX. Al principio de cada iteraci\'on, a este registro se mueve la cantidad de filas por 4, ya que, como se dijo anteriormente, la cantidad de componentes por p\'ixel es de 4 bytes. 

Finalmente, para realizar el pasaje de bytes de fuente a destino, se cuenta con dos \'indices: \textit{RDI} y \textit{RSI}. Estos registros se usan, respectivamente, para saber qu\'e 16 bytes de la imagen origen copiar y a qu\'e lugar de la imagen destino hacerlo. Como se necesita hacer un flip vertical, estos \'indices se comportan de la siguiente manera:

\begin{itemize}
	\item \textit{RDI}: entra al ciclo manteniendo el valor que se obtuvo como par\'ametro de la funci\'on, es decir, la direcci\'on de memoria donde comienzan los datos de la imagen fuente. Se ir\'a avanzado de a 16 bytes por la fila, y cada vez que se termina una fila, se posiciona como puntero al comienzo de la \textbf{fila siguiente} de la matriz de la imagen fuente. 
	
	\item \textit{RSI}: entra al ciclo con la posici\'on de memoria del comienzo de la \'ultima fila de la imagen destino. Avanza por las columnas en la iteraci\'on a lo largo de la fila para indicar d\'onde se deben trasladar los componentes. Al final de cada fila se posiciona como puntero al comienzo de la \textbf{fila anterior} de la matriz de la imagen destino. 
\end{itemize}

El recorrido a trav\'es de las filas es de la columna menos significativa a la m\'as significativa en ambas im\'agenes. En cambio, el recorrido a trav\'es de las filas es inverso: la imagen destino se recorre desde la \'ultima fila hasta la primera (de abajo para arriba), mientras que en la imagen fuente se recorre desde la primera a la \'ultima (de arriba para abajo).

El pasaje de bytes es simple. Se pasan 16 bytes desde [RDI + RBX] (RBX guarda el offset en la fila), a XMM0 y luego desde XMM0 [RSI], que va aumentando de a 16 bytes.

La \'ultima cuesti\'on a tener en cuenta es el borde al terminar una fila.

Si el ancho en bytes de la cantidad de p\'ixeles multiplicado por 4 no es m\'ultiplo de 16, puede ser que cuando se traten de pasar los \'ultimos bytes a destino, se est\'e leyendo (y escribiendo) memoria que no est\'e asignada a nuestro proceso. Consid\'erese el siguiente ejemplo: se ha recorrido toda una fila de 52 bytes, y se quieren pasar los \'ultimos cuatro bytes. Si realizamos el procedimiento habitual, nos encontrar\'iamos en la situaci\'on en la que al levantar el byte 48, 49, 50 y 51 a XMM0, tambi\'en se levantar\'ia los 12 bytes contiguos, que contienen padding o parte de la fila posterior (y en la \'ultima fila, potencialmente, memoria inv\'alida).

\begin{verbatim}

|b 48|b 49|b 50|b 51|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|

\end{verbatim}

Frente a este problema, lo que se hizo fue tratar el caso especial en el que hay que procesar menos de 16 bytes. Para ello, en el ciclo interno, se detecta si el contador $RAX$ es mayor que 0 y menor que 16. Si se trata de este caso, lo que se hace es volver los punteros $RDI$ y $RSI$ unos bytes detr\'as para procesar exactamente los \'ultimos 16 bytes. En el ejemplo anterior, en la \'ultima iteraci\'on, se procesar\'ian los siguientes bytes:

\begin{verbatim}

|b 36|b 37|b 38|b 39|b 40|b 41|b 42|b 43|b 44|b 45|b 46|b 47|b 48|b 49|b 50|b 51|

\end{verbatim}

Se muestra a continuaci\'on el pseudoc\'odigo de la implementaci\'on en ASM:

\begin{codesnippet}
\begin{verbatim}
    En R10 guardo src_row_size * offsety + 4*offsetx  // comienzo de la imagen a recortar
			
	
    En RAX guardo dst_row_size * tamy
	
    RSI += RAX // comienzo de la ultima fila de la imagen destino
	
    En R12d guardo tamy
	
    En RDX guardo 4 * tamx
    Mientras R12 != 0
        Mover a RBX, R10
        Mover a RAX, RDX
        Mientras RAX != 0
           Si RAX < 16
               RAX -= 16
               RBX += RAX
               RSI += RAX
               MOV RAX, 16	
           Si no
               Mover a XMM0 [RDI + RBX]
               RAX -= 16
               RBX += 16
               Mover a [RSI], XMM0
               ADD RDI, 16		
           FinSi			
       FinMientras
   FinMientras
	
	
\end{verbatim}
\end{codesnippet}

\subsubsection{An\'alisis de c\'odigo}

Al realizar un decompilado, se obtuvo el siguiente c\'odigo para la funci\'on cropflip codificada en C:

\begin{verbatim}
0000000000000000 <cropflip_c>:
   0:	55                   	push   rbp
   1:	48 89 e5             	mov    rbp,rsp
   4:	41 55                	push   r13
   6:	41 54                	push   r12
   8:	48 89 7d b8          	mov    QWORD PTR [rbp-0x48],rdi
   c:	48 89 75 b0          	mov    QWORD PTR [rbp-0x50],rsi
  10:	89 55 ac             	mov    DWORD PTR [rbp-0x54],edx
  13:	89 4d a8             	mov    DWORD PTR [rbp-0x58],ecx
  16:	44 89 45 a4          	mov    DWORD PTR [rbp-0x5c],r8d
  1a:	44 89 4d a0          	mov    DWORD PTR [rbp-0x60],r9d
  1e:	8b 45 a4             	mov    eax,DWORD PTR [rbp-0x5c]
  21:	48 63 d0             	movsxd rdx,eax
  24:	48 83 ea 01          	sub    rdx,0x1
  28:	48 89 55 d0          	mov    QWORD PTR [rbp-0x30],rdx
  2c:	48 63 d0             	movsxd rdx,eax
  2f:	49 89 d4             	mov    r12,rdx
  32:	41 bd 00 00 00 00    	mov    r13d,0x0
  38:	48 8b 55 b8          	mov    rdx,QWORD PTR [rbp-0x48]
  3c:	48 89 55 d8          	mov    QWORD PTR [rbp-0x28],rdx
  40:	8b 55 a0             	mov    edx,DWORD PTR [rbp-0x60]
  43:	48 63 ca             	movsxd rcx,edx
  46:	48 83 e9 01          	sub    rcx,0x1
  4a:	48 89 4d e0          	mov    QWORD PTR [rbp-0x20],rcx
  4e:	48 63 ca             	movsxd rcx,edx
  51:	49 89 ca             	mov    r10,rcx
  54:	41 bb 00 00 00 00    	mov    r11d,0x0
  5a:	48 8b 4d b0          	mov    rcx,QWORD PTR [rbp-0x50]
  5e:	48 89 4d e8          	mov    QWORD PTR [rbp-0x18],rcx
  62:	c7 45 c8 00 00 00 00 	mov    DWORD PTR [rbp-0x38],0x0
  69:	eb 7d                	jmp    e8 <cropflip_c+0xe8>
  6b:	c7 45 cc 00 00 00 00 	mov    DWORD PTR [rbp-0x34],0x0
  72:	eb 5e                	jmp    d2 <cropflip_c+0xd2>
  74:	8b 4d c8             	mov    ecx,DWORD PTR [rbp-0x38]
  77:	8b 75 18             	mov    esi,DWORD PTR [rbp+0x18]
  7a:	29 ce                	sub    esi,ecx
  7c:	89 f1                	mov    ecx,esi
  7e:	83 e9 01             	sub    ecx,0x1
  81:	48 63 f1             	movsxd rsi,ecx
  84:	48 63 ca             	movsxd rcx,edx
  87:	48 0f af f1          	imul   rsi,rcx
  8b:	48 8b 4d e8          	mov    rcx,QWORD PTR [rbp-0x18]
  8f:	48 8d 3c 0e          	lea    rdi,[rsi+rcx*1]
  93:	8b 4d 28             	mov    ecx,DWORD PTR [rbp+0x28]
  96:	8b 75 c8             	mov    esi,DWORD PTR [rbp-0x38]
  99:	01 f1                	add    ecx,esi
  9b:	48 63 f1             	movsxd rsi,ecx
  9e:	48 63 c8             	movsxd rcx,eax
  a1:	48 0f af f1          	imul   rsi,rcx
  a5:	48 8b 4d d8          	mov    rcx,QWORD PTR [rbp-0x28]
  a9:	48 01 ce             	add    rsi,rcx
  ac:	8b 4d 20             	mov    ecx,DWORD PTR [rbp+0x20]
  af:	44 8d 04 8d 00 00 00 	lea    r8d,[rcx*4+0x0]
  b6:	00 
  b7:	8b 4d cc             	mov    ecx,DWORD PTR [rbp-0x34]
  ba:	44 01 c1             	add    ecx,r8d
  bd:	48 63 c9             	movsxd rcx,ecx
  c0:	0f b6 34 0e          	movzx  esi,BYTE PTR [rsi+rcx*1]
  c4:	8b 4d cc             	mov    ecx,DWORD PTR [rbp-0x34]
  c7:	48 63 c9             	movsxd rcx,ecx
  ca:	40 88 34 0f          	mov    BYTE PTR [rdi+rcx*1],sil
  ce:	83 45 cc 01          	add    DWORD PTR [rbp-0x34],0x1
  d2:	8b 4d 10             	mov    ecx,DWORD PTR [rbp+0x10]
  d5:	c1 e1 02             	shl    ecx,0x2
  d8:	3b 4d cc             	cmp    ecx,DWORD PTR [rbp-0x34]
  db:	7f 97                	jg     74 <cropflip_c+0x74>
  dd:	c7 45 cc 00 00 00 00 	mov    DWORD PTR [rbp-0x34],0x0
  e4:	83 45 c8 01          	add    DWORD PTR [rbp-0x38],0x1
  e8:	8b 4d c8             	mov    ecx,DWORD PTR [rbp-0x38]
  eb:	3b 4d 18             	cmp    ecx,DWORD PTR [rbp+0x18]
  ee:	0f 8c 77 ff ff ff    	jl     6b <cropflip_c+0x6b>
  f4:	41 5c                	pop    r12
  f6:	41 5d                	pop    r13
  f8:	5d                   	pop    rbp
  f9:	c3                   	ret    
\end{verbatim}

Lo que se observa en primera instancia es que los par\'ametros de la funci\'on se pasan a la memoria de la pila, en posiciones menos significativas que su base dada por el registro RBP. Luego cada vez que se necesita obtener algunos de estos par\'ametros, se vuelven a traer los datos de la memoria asignada para tal fin.

Por otra parte se produce algo similar con las variables locales. Un ejemplo es el caso de las variables asignadas para el ciclo $i$ y $j$. Como se ve en las direcciones 62 y 6b se  inicializan estas variables en 0 en las posiciones de memoria reservadas para la pila [rbp-0x34] y [rbp-0x38]. En cada iteraci\'on, cuando se incrementan los \'indices, tambi\'en se direcciona a memoria, como se observa en las l\'ineas ce y c4. Por ejemplo:

\begin{verbatim}
add    DWORD PTR [rbp-0x38],0x1
\end{verbatim}

Este tipo de manejo es claramente ineficiente, ya que las operaciones se podr\'ian realizar en registros y nos evitar\'iamos los accesos a memoria, por m\'as que las posiciones buscadas ya se encuentren cacheadas.

Por otra parte, en ninguna instancia se hace uso de SSE. El c\'odigo compilado realiza todo en forma escalar, y no hace uso de la posibilidad de realizar operaciones en forma paralela. Este es el principal tema que mejora la implementaci\'on en assembler.

Lo que se debe tener en cuenta es que el compilador de gnu se est\'a ejecutando con el nivel de compilaci\'on por defecto, que corresponde al flag -O0. 
Se realiz\'o la experiencia de recompilar el c\'odigo indic\'andole -01 en el nivel de compilaci\'on en la variable de buildeo CXXFLAGS. El resultado fue el siguiente:

\begin{verbatim}
0000000000000000 <cropflip_c>:
   0:	41 55                	push   r13
   2:	41 54                	push   r12
   4:	55                   	push   rbp
   5:	53                   	push   rbx
   6:	44 8b 54 24 30       	mov    r10d,DWORD PTR [rsp+0x30]
   b:	45 85 d2             	test   r10d,r10d
   e:	7e 6c                	jle    7c <cropflip_c+0x7c>
  10:	8b 44 24 28          	mov    eax,DWORD PTR [rsp+0x28]
  14:	8d 1c 85 00 00 00 00 	lea    ebx,[rax*4+0x0]
  1b:	8b 44 24 38          	mov    eax,DWORD PTR [rsp+0x38]
  1f:	8d 2c 85 00 00 00 00 	lea    ebp,[rax*4+0x0]
  26:	41 83 ea 01          	sub    r10d,0x1
  2a:	44 8b 5c 24 40       	mov    r11d,DWORD PTR [rsp+0x40]
  2f:	4d 63 e8             	movsxd r13,r8d
  32:	4d 63 e1             	movsxd r12,r9d
  35:	44 8d 4c 1d 00       	lea    r9d,[rbp+rbx*1+0x0]
  3a:	eb 24                	jmp    60 <cropflip_c+0x60>
  3c:	48 63 c8             	movsxd rcx,eax
  3f:	41 0f b6 0c 08       	movzx  ecx,BYTE PTR [r8+rcx*1]
  44:	88 0a                	mov    BYTE PTR [rdx],cl
  46:	83 c0 01             	add    eax,0x1
  49:	48 83 c2 01          	add    rdx,0x1
  4d:	44 39 c8             	cmp    eax,r9d
  50:	75 ea                	jne    3c <cropflip_c+0x3c>
  52:	41 83 ea 01          	sub    r10d,0x1
  56:	41 83 c3 01          	add    r11d,0x1
  5a:	41 83 fa ff          	cmp    r10d,0xffffffff
  5e:	74 1c                	je     7c <cropflip_c+0x7c>
  60:	85 db                	test   ebx,ebx
  62:	7e ee                	jle    52 <cropflip_c+0x52>
  64:	4d 63 c3             	movsxd r8,r11d
  67:	4d 0f af c5          	imul   r8,r13
  6b:	49 01 f8             	add    r8,rdi
  6e:	89 e8                	mov    eax,ebp
  70:	49 63 d2             	movsxd rdx,r10d
  73:	49 0f af d4          	imul   rdx,r12
  77:	48 01 f2             	add    rdx,rsi
  7a:	eb c0                	jmp    3c <cropflip_c+0x3c>
  7c:	5b                   	pop    rbx
  7d:	5d                   	pop    rbp
  7e:	41 5c                	pop    r12
  80:	41 5d                	pop    r13
  82:	c3                   	ret    
\end{verbatim}

Se observ\'o, en primera instancia, que el c\'odigo es mucho m\'as corto, lo que supuso ya un tipo de optimizaci\'on. Por otra parte el manejo de las variables locales y de par\'ametros es diferente. Los par\'ametros se conservan en los registros. Asimismo, tambi\'en las variables locales usadas en los ciclos se conservan en los registros. Todo esto supone un gran optimizaci\'on, aunque b\'asica, en la cantidad de accesos a memoria. N\'otese que el flag -O1 es uno de los niveles m\'as bajos de optimizaci\'on. 

Para ofrecer un panorama m\'as amplio, se pasa revista a las principales opciones que ofrece el compilador de GNU:

\begin{itemize}
\item  O0: el c\'odigo no se optimiza. 

\item O1: se trata del nivel de optimizaci\'on m\'as bajo. Se trata de realizar una compilaci\'on r\'apida pero tambi\'en obtener un c\'odigo de menos l\'ineas y m\'as r\'apido.

\item O2:  Este es el nivel recomendado de optimización, cuando se trata de casos especiales en los que se quiere realizar cierto tipo de optimizaci\'on especial. Con -O2, el compilador intentará aumentar el rendimiento del código sin comprometer el tamaño. Si bien se intentar\'a realizar la compilaci\'on en forma r\'apida, el tiempo ser\'a superior al del flag -O2.
\item -O3: Con este flag se llega al nivel m\'as alto de optimizaci\'on. Se compromete a realizar t\'ecnicas de compilaci\'on que son costosas en t\'erminos de tiempo y memoria. El hecho de compilar con -O3 no garantiza una forma de mejorar el rendimiento y de hecho, en muchos casos puede hacer m\'as lento un sistema ya que genera binarios de gran tamaño y uso de memoria. -O3 puede llegar a romper unos paquetes, por lo que no se recomienda utilizarlo. El compilador activa los flags -fgcse-after-reload, -finline-functions, -fipa-cp-clone, -fpredictive-commoning, -ftree-vectorize, and -funswitch-loops options adem\'as de las optimizaciones propias de -O2.
\end{itemize}

Existen algunos flags para obtener cierto tipos especiales de optimizaci\'on:

\begin{itemize}
\item Os: Est\'a orientado a reducir el tamaño del c\'odigo. Activa todas las opciones de -O2 que no aumenten el tamaño del código generado. Se usa en m\'aquinas que tiene pocos recursos de almacenamiento

-Ofast: Trata de realizar optimizaciones con los flags -ffast-math, -fno-protect-parens y -fstack-arrays, adem\'as de las optimizaciones de -O3. Esta opción rompe el cumplimiento de estándares estrictos y no se recomienda.
\end{itemize}

Se pueden mencionar algunas t\'ecnicas gen\'ericas de optimizaci\'on que usan los compiladores, como \textbf{la optimizaci\'on de ciclos}. 

Este tipo de optimizaci\'on puede usar estrategias como \textit{\textbf{loop unrolling}}, es decir la duplicaci\'on del cuerpo de un ciclo m\'ultiples veces, de manera de reducir el overhead involucrado al final de cada iteraci\'on en verificar si se termin\'o el ciclo y en el manejo de contadores. Si se despliega compĺetamente el ciclo, en el caso extremo, se eliminar\'ia por completo el overhead. 

Otro tipo de optimizaci\'on de ciclos es el \textbf{\textit{pipelining de software}}. El ciclo se reordena de tal manera que el trabajo hecho en una iteraci\'on se separa y se realiza en varias iteraciones con el objetivo de reducir la latencia entre la carga y el uso de valores.

Otro tipo de optimizaci\'on es la del \textbf{flujo de datos (data-flow optimization)}.

Un ejemplo ser\'ia \textbf{\textit{la eliminaci\'on de subexpresiones comunes}}. Si una subexpresi\'on se usa varias veces en un c\'alculo, se calcula una sola vez y se usa varias veces sin recalcularlo. Por ejemplo, en la operaci\'on $(a + b) \times 2 + (a + b)$, $(a + b)$ se calcular\'ia una sola vez.


Antes de dejar esta parte de an\'alisis de c\'odigo, una cuesti\'on a tener en cuenta es que en el c\'odigo desensamblado aparecen otras funciones. Esta l\'ogica corresponde a informaci\'on de debug\footnote{Se usa DWARF. DWARF es un est\'andar para manejar los datos de debug. Se pens\'o originalmente como un complemento del file format elf.}.

As\'i se encuentra en la salida del objdump la siguiente informaci\'on:
\begin{itemize}
	\item .debug_abbrev - Abreviaciones usadas en la section .debug_info 
    \item .debug_aranges - Tabla para unir las direcciones a las unidades de compilación
    \item .debug_frame - Informaci\'on del call frame.
    \item .debug_info - La informaci\'on base del debug seg\'un el est\'andar DWARF.
    \item .debug_line - informaci\'on sobre la l\'ineas de programa
    \item .debug_ranges - rangos de direcciones usadas en los atributos de rango DW_AT_
    \item .debug_str - la tabla de strings de la informaci\'on de debug
\end{itemize}

\subsubsection{Experimentos y An\'alisis de resultado}

En el siguiente experimento, se midi\'o el tiempo de ejecuci\'on de cropflip 10 veces para la versi\'on de C sin optimizaciones para im\'agenes de $100 \times 100$, de $200 \times 200$ y de $300 \times 300$:

Los resultados fueron los siguientes:
\\
\\
$100 \times 100$
\\
\\

    \begin{tabular}{ | l | l |}
    \hline
	Caso & Tiempo en ms \\ \hline
	1 & 2400 \\ \hline
	2 & 2544 \\ \hline
	3 & 2260 \\ \hline
	4 & 2172 \\ \hline
	5 & 2356 \\ \hline
	6 & 2280 \\ \hline
	7 & 2152 \\ \hline
	8 & 2244 \\ \hline
	9 & 2560 \\ \hline
	10 & 2200 \\ \hline
	\textbf{Promedio} & 2316.8 \\ \hline
	\textbf{Varianza} & 21208.18 \\ \hline
    \end{tabular}
\\
\\
$200 \times 200$
\\
\\
    \begin{tabular}{ | l | l |}
    \hline
	Caso & Tiempo en ms \\ \hline
	1 & 19844 \\ \hline
	2 & 20629 \\ \hline
	3 & 20458 \\ \hline
	4 & 47604 \\ \hline
	5 & 20612 \\ \hline
	6 & 19948 \\ \hline
	7 & 25436 \\ \hline
	8 & 19856 \\ \hline
	9 & 19760 \\ \hline
	10 & 20000 \\ \hline
	\textbf{Promedio} & 23414.7 \\ \hline
	\textbf{Varianza} & 75112719.5 7\\ \hline
    \end{tabular}
\\
\\
$300 \times 300$
\\
\\
    \begin{tabular}{ | l | l |}
    \hline
	Caso & Tiempo en ms \\ \hline
	1 & 32700 \\ \hline
	2 & 31948 \\ \hline
	3 & 32432 \\ \hline
	4 & 32876 \\ \hline
	5 & 41696 \\ \hline
	6 & 32692 \\ \hline
	7 & 32088 \\ \hline
	8 & 32208 \\ \hline
	9 & 32724 \\ \hline
	10 & 32724 \\ \hline
	\textbf{Promedio} & 33363.6 \\ \hline
	\textbf{Varianza} & 8665900.27 \\ \hline
    \end{tabular}
\\
\\
Los experimentos se realizaron en un Intel i3, que tiene 2 cores con 1 thread cada uno. Las siguientes mediciones se hicieron con dos procesos basados en en un programa en C que aumenta un contador en un ciclo infinito:
\\
\\
$100 \times 100$
\\
\\

    \begin{tabular}{ | l | l |}
    \hline
	Caso & Tiempo en ms \\ \hline
	1 & 2316 \\ \hline
	2 & 3068 \\ \hline
	3 & 2608 \\ \hline
	4 & 3568 \\ \hline
	5 & 2876 \\ \hline
	6 & 2864 \\ \hline
	7 & 3268 \\ \hline
	8 & 3108 \\ \hline
	9 & 3084 \\ \hline
	10 & 3248 \\ \hline
	\textbf{Promedio} & 3000.8 \\ \hline
	\textbf{Varianza} & 126075.73 \\ \hline
    \end{tabular}
\\
\\
$200 \times 200$
\\
\\
    \begin{tabular}{ | l | l |}
    \hline
	Caso & Tiempo en ms \\ \hline
1 & 23048 \\ \hline
2 & 22800 \\ \hline
3 & 23080 \\ \hline
4 & 22728 \\ \hline
5 & 23192 \\ \hline
6 & 23484 \\ \hline
7 & 19972 \\ \hline
8 & 20012 \\ \hline
9 & 23292 \\ \hline
10 & 23408 \\ \hline
	\textbf{Promedio} & 22501.6 \\ \hline
	\textbf{Varianza} & 1806493.16 7\\ \hline
    \end{tabular}
\\
\\
$300 \times 300$
\\
\\
    \begin{tabular}{ | l | l |}
    \hline
	Caso & Tiempo en ms \\ \hline
1 & 36204 \\ \hline
2 & 35864 \\ \hline
3 & 36904 \\ \hline
4 & 37048 \\ \hline
5 & 37612 \\ \hline
6 & 36080 \\ \hline
7 & 36140 \\ \hline
8 & 36084 \\ \hline
9 & 32496 \\ \hline
10 & 36108 \\ \hline
	\textbf{Promedio} & 36054 \\ \hline
	\textbf{Varianza} & 1874194.67 \\ \hline
    \end{tabular}
\\
\\
Tomando como outliers los dos mediciones m\'as altas y las dos m\'as bajas, los promedios quedaron as\'i:
\\
\\
Sin procesos de fondo
\\
\\
    \begin{tabular}{ | l | l | l |}
    \hline
	Dimension & Promedio & Varianza en ms \\ \hline
$100 \times 100$ & 2290 & 5534.4 \\ \hline
$200 \times 200$ & 20250.5 & 125377.5 \\ \hline
$300 \times 300$ & 32504.66 & 53756.27 \\ \hline
    \end{tabular}
\\
\\
Con procesos de fondo
\\
\\
    \begin{tabular}{ | l | l | l |}
    \hline
	Dimension & Promedio & Varianza en ms \\ \hline
$100 \times 100$ & 3041.33 & 21693.86 \\ \hline
$200 \times 200$ & 23023.33 & 48309.87 \\ \hline
$300 \times 300$ & 36253.33 & 103697.07 \\ \hline
    \end{tabular}

\begin{figure}[H]
  \begin{center}
   \includegraphics[scale=0.66]{imagenes/promedios.png}
  \end{center}
\end{figure}

\begin{figure}[H]
  \begin{center}
   \includegraphics[scale=0.66]{imagenes/varianzas.png}
  \end{center}
\end{figure}

Se observa que el peso de los procesos de fondo no afecta la forma en la que crece el promedio a medida que se fue aumentando el tamaño de la imagen, si bien la ejecuci\'on demora m\'as ciclos de reloj. Por otra parte, la varianza en el caso del experimento sin procesos de fondo no tuvo un crecimiento uniforme en los tres tamaños de imagen observados.

En el siguiente experimento, se midi\'o el tiempo de ejecuci\'on de cropflip 10 veces para la versi\'on en ASM y en C con los distintos flags de optimizaci\'on para im\'agenes de $100 \times 100$, de $200 \times 200$ y de $300 \times 300$. Se extrajeron 4 outliers, los dos de m\'axima duraci\'on y los dos de menos duraci\'on y se obtuvo un promedio:
\\
\\
    \begin{tabular}{ | l | l | l | l | l | l |}
    \hline
	Dimensi\'on & ASM & -O0 & -01 & -O2 & -O3 \\ \hline
	Promedio 100x100 & 1,909.2 & 2,290 & 2,160 & 2,156 & 2,188 \\ \hline
	Promedio 200x200 & 19,004 & 20,250.5 & 20,180 & 20,028 & 21,540 \\ \hline
	Promedio 300x300 & 30,864 & 32,504.66 & 32,376 & 32,200 & 32,500 \\ \hline
    \end{tabular}
\\
\\
\begin{figure}[H]
  \begin{center}
   \includegraphics[scale=0.66]{imagenes/grafico1-2.png}
  \end{center}
\end{figure}

Se observa que la funci\'on en assembler supera en performance temporal a las dem\'as. Un detalle a tener en cuenta es que la optimizaci\'on con el flag -O3 es la que peor se comporta en nuestro programa en C con respecto a las otras optimaziones.

En el siguiente experimento, se agregaron 4, 8 y 16 instrucciones aritm\'eticas y de acceso a memoria adicionales en cada iteraci\'on en la versi\'on de assembler y se compararon con los resultados dados por la versi\'on original. Usamos la imagen de 100x100. Las instrucciones de acceso a memoria que utilizamos fueron las siguientes: 

\begin{verbatim}
    MOV [RSP], RAX
    MOV RAX, [RSP]
    MOV [RSP], RAX
    MOV RAX, [RSP]
    MOV [RSP], RAX
    MOV RAX, [RSP]
\end{verbatim}

y en el caso de las instrucciones aritm\'eticas simplemente hicimos ADD a un registro que no se usa.

Los resultados fueron los siguientes:
\\
\\
    \begin{tabular}{ | l | l | l |}
    \hline
	 Cantidad de instrucciones adicionales & Instrucciones aritm\'eticas & Instrucciones de memoria \\ \hline
4 & 2,778.67 & 2,792 \\ \hline
8 & 3,376 & 4,796 \\ \hline
16 & 4,157.83 & 6,769.67 \\ \hline
    \end{tabular}
\\
\\
\begin{figure}[H]
  \begin{center}
   \includegraphics[scale=0.66]{imagenes/grafico1-1.png}
  \end{center}
\end{figure}

Ya en esta instancia, se observa un mayor peso de las instrucciones de memoria del uso del bus sobre el uso de l\'ogica del cpu. Estas pruebas fueron realizadas en un equipo con la siguiente jerarqu\'ias de cache:

\begin{verbatim}

salida de dmidecode -t cache

Cache Information
	Socket Designation: CPU Internal L2
	Configuration: Enabled, Not Socketed, Level 2
	Operational Mode: Write Through
	Location: Internal
	Installed Size: 512 kB
	Maximum Size: 512 kB
	Supported SRAM Types:
		Unknown
	Installed SRAM Type: Unknown
	Speed: Unknown
	Error Correction Type: Multi-bit ECC
	System Type: Unified
	Associativity: 8-way Set-associative

Handle 0x0009, DMI type 7, 19 bytes
Cache Information
	Socket Designation: CPU Internal L1
	Configuration: Enabled, Not Socketed, Level 1
	Operational Mode: Write Through
	Location: Internal
	Installed Size: 128 kB
	Maximum Size: 128 kB
	Supported SRAM Types:
		Unknown
	Installed SRAM Type: Unknown
	Speed: Unknown
	Error Correction Type: Parity
	System Type: Data
	Associativity: 8-way Set-associative

Handle 0x000A, DMI type 7, 19 bytes
Cache Information
	Socket Designation: CPU Internal L3
	Configuration: Enabled, Not Socketed, Level 3
	Operational Mode: Write Back
	Location: Internal
	Installed Size: 3072 kB
	Maximum Size: 3072 kB
	Supported SRAM Types:
		Unknown
	Installed SRAM Type: Unknown
	Speed: Unknown
	Error Correction Type: Multi-bit ECC
	System Type: Unified
	Associativity: 12-way Set-associative

 
\end{verbatim}

Si bien se observa un mayor overhead temporal en el caso de los accesos a memoria, se debe tener en cuenta que gran parte de las instrucciones agregadas usan la cache, ya que se accede siempre a las mismas direcciones. Para evaluar cu\'al es el peso real del acceso a bus se tomaron en cuenta otras consideraciones.

La l\'inea de cache en el ambiente de pruebas tiene un tamaño de 64 bytes\footnote{se obtuvo de /sys/devices/system/cpu/cpu0/cache/index0}. N\'otese entonces que la cache L1, por ser asociativa por 8 v\'ias, tiene 16Kb por conjunto (tamaño total de 128Kb). Si el tamaño de l\'inea de la cache es de 64 bytes, tenemos que cada l\'inea tiene 256 bytes. Para generar m\'as misses en la cache de L1 lo que se bizo fue realizar operaciones de acceso a memoria subiendo en la pila de a 256 bytes. As\'i las instrucciones que se ejecutaron en cada iteraci\'on son las siguientes (empezando con R11 en 0 y rest\'andole 256 bytes en cada paso del ciclo)

\begin{verbatim}
    SUB R11, 256
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP+ R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
\end{verbatim}

La diferencia de tiempo es considerable si se la compara con el mismo programa, en donde  no se resta nada al lugar de la pila al que voy a acceder en cada iteraci\'on. Es decir: restando cero al offset de la pila:

\begin{verbatim}
    SUB R11, 0
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP+ R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
    MOV [RSP + R11], RAX
    MOV RAX, [RSP + R11]
\end{verbatim}

Estos son los resultados obtenidos:
\\
\\
    \begin{tabular}{ | l | l | l |}
    \hline
	 Cantidad de instrucciones adicionales &  implementacion orientada a misses &  implementacion base \\ \hline
4 & 14460 & 2,792 \\ \hline
8 & 17192 & 4,796 \\ \hline
16 & 24816 & 6,769.67 \\ \hline
    \end{tabular}
\\
\\
\begin{figure}[H]
  \begin{center}
   \includegraphics[scale=0.66]{imagenes/grafico1-3.png}
  \end{center}
\end{figure}
